

import pygame as pg
from .. import tool
from .. import constants as c


class Zombie(pg.sprite.Sprite):
    def __init__(self, x, y, name, health, head_group=None, damage=1):
        pg.sprite.Sprite.__init__(self)

        self.name = name  # 设置僵尸的名称
        self.frames = []  # 初始化图像帧列表
        self.frame_index = 0  # 初始化图像帧索引
        self.loadImages()  # 加载图像

        self.frame_num = len(self.frames)  # 获取图像帧数量

        self.image = self.frames[self.frame_index]  # 设置当前图像
        self.rect = self.image.get_rect()  # 获取图像矩形
        self.rect.centerx = x  # 设置 x 坐标
        self.rect.bottom = y  # 设置底部 y 坐标

        self.health = health  # 设置僵尸的健康值
        self.damage = damage  # 设置僵尸的伤害值
        self.dead = False  # 是否死亡
        self.losHead = False  # 是否失去头部
        self.helmet = False  # 是否戴着头盔
        self.head_group = head_group  # 头部组

        self.walk_timer = 0  # 行走计时器
        self.animate_timer = 0  # 动画计时器
        self.attack_timer = 0  # 攻击计时器
        self.state = c.WALK  # 设置状态为行走
        self.animate_interval = 150  # 动画间隔
        self.ice_slow_ratio = 1  # 冰冻减速比率
        self.ice_slow_timer = 0  # 冰冻减速计时器
        self.hit_timer = 0  # 受击计时器
        self.speed = 1  # 速度
        self.freeze_timer = 0  # 冻结计时器
        self.is_hypno = False  # 是否被催眠，如果被催眠则攻击其他僵尸（当它吃了 HypnoShroom）

    def loadFrames(self, frames, name, image_x, colorkey=c.BLACK):
        # 从图像资源中加载图像帧并添加到帧列表中
        frame_list = tool.GFX[name]  # 从图像资源中获取指定名称的图像列表
        rect = frame_list[0].get_rect()  # 获取图像帧的矩形区域
        width, height = rect.w, rect.h  # 获取图像帧的宽度和高度
        width -= image_x  # 调整宽度以剔除图像中不需要的部分

        # 遍历图像列表，加载图像帧并添加到帧列表中
        for frame in frame_list:
            frames.append(tool.get_image(frame, image_x, 0, width, height, colorkey))

    def update(self, game_info):
        # 更新僵尸的状态和动画
        self.current_time = game_info[c.CURRENT_TIME]  # 获取当前游戏时间
        self.handleState()  # 处理当前状态
        self.updateIceSlow()  # 更新冰冻状态
        self.animation()  # 更新动画

    def handleState(self):
        # 处理僵尸的不同状态
        if self.state == c.WALK:
            self.walking()  # 处理行走状态
        elif self.state == c.ATTACK:
            self.attacking()  # 处理攻击状态
        elif self.state == c.DIE:
            self.dying()  # 处理死亡状态
        elif self.state == c.FREEZE:
            self.freezing()  # 处理冻结状态

    def walking(self):
        # 处理僵尸行走状态
        if self.health <= 0:
            self.setDie()  # 如果健康值小于等于0，设置为死亡状态
        elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead:
            self.changeFrames(self.losthead_walk_frames)  # 如果健康值低于丢失头部的健康值，设置为丢失头部行走状态
            self.setLostHead()  # 标记为丢失头部状态
        elif self.health <= c.NORMAL_HEALTH and self.helmet:
            self.changeFrames(self.walk_frames)  # 如果健康值低于普通健康值且佩戴头盔，设置为行走状态
            self.helmet = False  # 取消头盔状态
            if self.name == c.NEWSPAPER_ZOMBIE:
                self.speed = 2  # 如果是报纸僵尸，速度加倍

        # 更新行走计时器
        if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()):
            self.walk_timer = self.current_time
            if self.is_hypno:
                self.rect.x += self.speed  # 如果被催眠，向前移动
            else:
                self.rect.x -= self.speed  # 否则向后移动

    def attacking(self):
        # 处理僵尸攻击状态
        if self.health <= 0:
            self.setDie()  # 如果健康值小于等于0，设置为死亡状态
        elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead:
            self.changeFrames(self.losthead_attack_frames)  # 如果健康值低于丢失头部的健康值，设置为丢失头部攻击状态
            self.setLostHead()  # 标记为丢失头部状态
        elif self.health <= c.NORMAL_HEALTH and self.helmet:
            self.changeFrames(self.attack_frames)  # 如果健康值低于普通健康值且佩戴头盔，设置为攻击状态
            self.helmet = False  # 取消头盔状态

        # 更新攻击计时器
        if (self.current_time - self.attack_timer) > (c.ATTACK_INTERVAL * self.getTimeRatio()):
            if self.prey.health > 0:
                if self.prey_is_plant:
                    self.prey.setDamage(self.damage, self)  # 如果目标是植物，设置伤害并指定攻击者
                else:
                    self.prey.setDamage(self.damage)  # 否则只设置伤害
            self.attack_timer = self.current_time

        # 如果目标健康值小于等于0，设置为行走状态
        if self.prey.health <= 0:
            self.prey = None
            self.setWalk()

    def dying(self):#死亡状态；不同的状态展示相应的图像帧
        pass

    def freezing(self):#冻结状态
        if self.health <= 0:  # 如果健康值小于等于0
            self.setDie()  # 将僵尸设置为死亡状态
        elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead:  # 如果健康值低于丢失头部的健康值且未丢失头部
            if self.old_state == c.WALK:  # 如果之前的状态为行走
                self.changeFrames(self.losthead_walk_frames)  # 切换到丢失头部行走的帧集合
            else:
                self.changeFrames(self.losthead_attack_frames)  # 否则切换到丢失头部攻击的帧集合
            self.setLostHead()  # 设置僵尸为丢失头部状态
        if (self.current_time - self.freeze_timer) > c.FREEZE_TIME:  # 如果冻结时间超过规定的冻结时间
            self.setWalk()  # 设置僵尸为行走状态

    def setLostHead(self):
        self.losHead = True  # 设置僵尸为丢失头部状态
        if self.head_group is not None:  # 如果头部组不为空
            self.head_group.add(ZombieHead(self.rect.centerx, self.rect.bottom))  # 在指定位置添加僵尸头部对象

    def changeFrames(self, frames):
        '''change image frames and modify rect position'''
        self.frames = frames
        self.frame_num = len(self.frames)
        self.frame_index = 0

        bottom = self.rect.bottom  # 保存矩形底部坐标
        centerx = self.rect.centerx  # 保存矩形中心x坐标
        self.image = self.frames[self.frame_index]  # 设置当前图像为第一帧
        self.rect = self.image.get_rect()  # 根据当前图像获取矩形
        self.rect.bottom = bottom  # 恢复矩形底部坐标
        self.rect.centerx = centerx  # 恢复矩形中心x坐标

    def animation(self):
        if self.state == c.FREEZE:  # 如果僵尸处于冻结状态
            self.image.set_alpha(192)  # 设置图像透明度为192
            return

        if (self.current_time - self.animate_timer) > (self.animate_interval * self.getTimeRatio()):
            self.frame_index += 1
            if self.frame_index >= self.frame_num:
                if self.state == c.DIE:
                    self.kill()
                    return
                self.frame_index = 0
            self.animate_timer = self.current_time

        self.image = self.frames[self.frame_index]
        if self.is_hypno:  # 如果僵尸被催眠
            self.image = pg.transform.flip(self.image, True, False)  # 翻转图像
        if (self.current_time - self.hit_timer) >= 200:  # 如果距离上次受击已经超过200毫秒
            self.image.set_alpha(255)  # 设置图像完全可见
        else:
            self.image.set_alpha(192)# 否则设置图像透明度为192

    def getTimeRatio(self):
        return self.ice_slow_ratio # 返回时间比率

    def setIceSlow(self):
         #当受到冰子弹伤害时，减缓僵尸的攻击或行走速度
        self.ice_slow_timer = self.current_time
        self.ice_slow_ratio = 2

    def updateIceSlow(self):
        if self.ice_slow_ratio > 1:  # 如果冰冻减速比率大于1
            if (self.current_time - self.ice_slow_timer) > c.ICE_SLOW_TIME:  # 如果距离上次冰冻已经超过规定的冰冻时间
                self.ice_slow_ratio = 1  # 将冰冻减速比率设置为1

    def setDamage(self, damage, ice=False):
        self.health -= damage  # 减去伤害值
        self.hit_timer = self.current_time  # 设置受击计时器为当前时间
        if ice:  # 如果受到冰冻伤害
            self.setIceSlow()  # 调用减缓减速方法

    def setWalk(self):
        self.state = c.WALK
        self.animate_interval = 150

        if self.helmet:
            self.changeFrames(self.helmet_walk_frames)
        elif self.losHead:
            self.changeFrames(self.losthead_walk_frames)
        else:
            self.changeFrames(self.walk_frames)

    def setAttack(self, prey, is_plant=True):
        self.prey = prey  # 设置被攻击对象prey can be plant or other zombies
        self.prey_is_plant = is_plant
        self.state = c.ATTACK
        self.attack_timer = self.current_time
        self.animate_interval = 100

        if self.helmet:
            self.changeFrames(self.helmet_attack_frames)
        elif self.losHead:
            self.changeFrames(self.losthead_attack_frames)
        else:
            self.changeFrames(self.attack_frames)

    def setDie(self):
        self.state = c.DIE# 设置状态为死亡
        self.animate_interval = 200
        self.changeFrames(self.die_frames)

    def setBoomDie(self):
        self.state = c.DIE
        self.animate_interval = 200
        self.changeFrames(self.boomdie_frames) # 更改帧集合为爆炸死亡帧集合

    def setFreeze(self, ice_trap_image):
        self.old_state = self.state
        self.state = c.FREEZE
        self.freeze_timer = self.current_time
        self.ice_trap_image = ice_trap_image # 设置冰冻陷阱图像
        self.ice_trap_rect = ice_trap_image.get_rect() # 获取冰冻陷阱图像的矩形
        self.ice_trap_rect.centerx = self.rect.centerx
        self.ice_trap_rect.bottom = self.rect.bottom

    def drawFreezeTrap(self, surface):
        if self.state == c.FREEZE:# 如果僵尸处于冻结状态
            surface.blit(self.ice_trap_image, self.ice_trap_rect) # 在表面上绘制冰冻陷阱图像

    def setHypno(self):
        self.is_hypno = True # 设置为催眠状态
        self.setWalk() # 设置为行走状态

class ZombieHead(Zombie):
    def __init__(self, x, y):
        Zombie.__init__(self, x, y, c.ZOMBIE_HEAD, 0)
        self.state = c.DIE # 初始状态为死亡

    def loadImages(self):
        self.die_frames = []
        die_name =  self.name
        self.loadFrames(self.die_frames, die_name, 0)
        self.frames = self.die_frames

    def setWalk(self):
        self.animate_interval = 100


class NormalZombie(Zombie):  # 定义NormalZombie类，继承自Zombie类
    def __init__(self, x, y, head_group):  # 初始化方法，接受x、y坐标和head_group参数
        Zombie.__init__(self, x, y, c.NORMAL_ZOMBIE, c.NORMAL_HEALTH,
                        head_group)  # 调用父类Zombie的初始化方法，传入x、y坐标、常量NORMAL_ZOMBIE、NORMAL_HEALTH和head_group参数

    def loadImages(self):  # 定义加载图像的方法
        self.walk_frames = []  # 初始化行走帧集合
        self.attack_frames = []  # 初始化攻击帧集合
        self.losthead_walk_frames = []  # 初始化失去头部后的行走帧集合
        self.losthead_attack_frames = []  # 初始化失去头部后的攻击帧集合
        self.die_frames = []  # 初始化死亡帧集合
        self.boomdie_frames = []  # 初始化爆炸死亡帧集合

        walk_name = self.name  # 获取行走帧的名称
        attack_name = self.name + 'Attack'  # 获取攻击帧的名称
        losthead_walk_name = self.name + 'LostHead'  # 获取失去头部后的行走帧的名称
        losthead_attack_name = self.name + 'LostHeadAttack'  # 获取失去头部后的攻击帧的名称
        die_name = self.name + 'Die'  # 获取死亡帧的名称
        boomdie_name = c.BOOMDIE  # 获取爆炸死亡帧的名称

        frame_list = [self.walk_frames, self.attack_frames, self.losthead_walk_frames,  # 定义帧集合列表
                      self.losthead_attack_frames, self.die_frames, self.boomdie_frames]
        name_list = [walk_name, attack_name, losthead_walk_name,  # 定义帧名称列表
                     losthead_attack_name, die_name, boomdie_name]

        for i, name in enumerate(name_list):  # 遍历帧名称列表
            self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'])  # 调用loadFrames方法加载帧图像，传入帧集合、名称和x坐标

        self.frames = self.walk_frames  # 设置当前帧集合为行走帧集合


class ConeHeadZombie(Zombie):#路障僵尸
    def __init__(self, x, y, head_group):
        Zombie.__init__(self, x, y, c.CONEHEAD_ZOMBIE, c.CONEHEAD_HEALTH, head_group)
        self.helmet = True

    def loadImages(self):
        self.helmet_walk_frames = []
        self.helmet_attack_frames = []
        self.walk_frames = []
        self.attack_frames = []
        self.losthead_walk_frames = []
        self.losthead_attack_frames = []
        self.die_frames = []
        self.boomdie_frames = []

        helmet_walk_name = self.name  # 获取头盔行走帧的名称
        helmet_attack_name = self.name + 'Attack'  # 获取头盔攻击帧的名称
        walk_name = c.NORMAL_ZOMBIE  # 获取行走帧的名称
        attack_name = c.NORMAL_ZOMBIE + 'Attack'  # 获取攻击帧的名称
        losthead_walk_name = c.NORMAL_ZOMBIE + 'LostHead'  # 获取失去头部后的行走帧的名称
        losthead_attack_name = c.NORMAL_ZOMBIE + 'LostHeadAttack'  # 获取失去头部后的攻击帧的名称
        die_name = c.NORMAL_ZOMBIE + 'Die'  # 获取死亡帧的名称
        boomdie_name = c.BOOMDIE  # 获取爆炸死亡帧的名称

        frame_list = [self.helmet_walk_frames, self.helmet_attack_frames,
                      self.walk_frames, self.attack_frames, self.losthead_walk_frames,
                      self.losthead_attack_frames, self.die_frames, self.boomdie_frames]
        name_list = [helmet_walk_name, helmet_attack_name,
                     walk_name, attack_name, losthead_walk_name,
                     losthead_attack_name, die_name, boomdie_name]

        for i, name in enumerate(name_list):
            self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'])

        self.frames = self.helmet_walk_frames # 设置当前帧集合为头盔行走帧集合

class BucketHeadZombie(Zombie):#桶头僵尸
    def __init__(self, x, y, head_group):
        Zombie.__init__(self, x, y, c.BUCKETHEAD_ZOMBIE, c.BUCKETHEAD_HEALTH, head_group)
        self.helmet = True

    def loadImages(self):
        self.helmet_walk_frames = []
        self.helmet_attack_frames = []
        self.walk_frames = []
        self.attack_frames = []
        self.losthead_walk_frames = []
        self.losthead_attack_frames = []
        self.die_frames = []
        self.boomdie_frames = []

        helmet_walk_name = self.name
        helmet_attack_name = self.name + 'Attack'
        walk_name = c.NORMAL_ZOMBIE
        attack_name = c.NORMAL_ZOMBIE + 'Attack'
        losthead_walk_name = c.NORMAL_ZOMBIE + 'LostHead'
        losthead_attack_name = c.NORMAL_ZOMBIE + 'LostHeadAttack'
        die_name = c.NORMAL_ZOMBIE + 'Die'
        boomdie_name = c.BOOMDIE

        frame_list = [self.helmet_walk_frames, self.helmet_attack_frames,
                      self.walk_frames, self.attack_frames, self.losthead_walk_frames,
                      self.losthead_attack_frames, self.die_frames, self.boomdie_frames]
        name_list = [helmet_walk_name, helmet_attack_name,
                     walk_name, attack_name, losthead_walk_name,
                     losthead_attack_name, die_name, boomdie_name]

        for i, name in enumerate(name_list):
            self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'])

        self.frames = self.helmet_walk_frames


class FlagZombie(Zombie):  # 定义旗子僵尸类，继承自Zombie类
    def __init__(self, x, y, head_group):  # 初始化方法，接受x、y坐标和head_group参数
        Zombie.__init__(self, x, y, c.FLAG_ZOMBIE, c.FLAG_HEALTH,
                        head_group)  # 调用父类Zombie的初始化方法，传入x、y坐标、常量FLAG_ZOMBIE、FLAG_HEALTH和head_group参数

    def loadImages(self):  # 定义加载图像的方法
        self.walk_frames = []  # 初始化行走帧集合
        self.attack_frames = []  # 初始化攻击帧集合
        self.losthead_walk_frames = []  # 初始化失去头部后的行走帧集合
        self.losthead_attack_frames = []  # 初始化失去头部后的攻击帧集合
        self.die_frames = []  # 初始化死亡帧集合
        self.boomdie_frames = []  # 初始化爆炸死亡帧集合

        walk_name = self.name  # 获取行走帧的名称
        attack_name = self.name + 'Attack'  # 获取攻击帧的名称
        losthead_walk_name = self.name + 'LostHead'  # 获取失去头部后的行走帧的名称
        losthead_attack_name = self.name + 'LostHeadAttack'  # 获取失去头部后的攻击帧的名称
        die_name = c.NORMAL_ZOMBIE + 'Die'  # 获取死亡帧的名称
        boomdie_name = c.BOOMDIE  # 获取爆炸死亡帧的名称

        frame_list = [self.walk_frames, self.attack_frames,  # 定义帧集合列表
                      self.losthead_walk_frames, self.losthead_attack_frames,
                      self.die_frames, self.boomdie_frames]
        name_list = [walk_name, attack_name,  # 定义帧名称列表
                     losthead_walk_name, losthead_attack_name,
                     die_name, boomdie_name]

        for i, name in enumerate(name_list):  # 遍历帧名称列表
            self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'])  # 调用loadFrames方法加载帧图像，传入帧集合、名称和x坐标

        self.frames = self.walk_frames  # 设置当前帧集合为行走帧集合


class NewspaperZombie(Zombie):  # 定义报纸僵尸类，继承自Zombie类
    def __init__(self, x, y, head_group):  # 初始化方法，接受x、y坐标和head_group参数
        Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, c.NEWSPAPER_HEALTH,
                        head_group)  # 调用父类Zombie的初始化方法，传入x、y坐标、常量NEWSPAPER_ZOMBIE、NEWSPAPER_HEALTH和head_group参数
        self.helmet = True  # 设置头盔属性为True

    def loadImages(self):  # 定义加载图像的方法
        self.helmet_walk_frames = []  # 初始化头盔行走帧集合
        self.helmet_attack_frames = []  # 初始化头盔攻击帧集合
        self.walk_frames = []  # 初始化行走帧集合
        self.attack_frames = []  # 初始化攻击帧集合
        self.losthead_walk_frames = []  # 初始化失去头部后的行走帧集合
        self.losthead_attack_frames = []  # 初始化失去头部后的攻击帧集合
        self.die_frames = []  # 初始化死亡帧集合
        self.boomdie_frames = []  # 初始化爆炸死亡帧集合

        helmet_walk_name = self.name  # 获取头盔行走帧的名称
        helmet_attack_name = self.name + 'Attack'  # 获取头盔攻击帧的名称
        walk_name = self.name + 'NoPaper'  # 获取无报纸的行走帧的名称
        attack_name = self.name + 'NoPaperAttack'  # 获取无报纸的攻击帧的名称
        losthead_walk_name = self.name + 'LostHead'  # 获取失去头部后的行走帧的名称
        losthead_attack_name = self.name + 'LostHeadAttack'  # 获取失去头部后的攻击帧的名称
        die_name = self.name + 'Die'  # 获取死亡帧的名称
        boomdie_name = c.BOOMDIE  # 获取爆炸死亡帧的名称

        frame_list = [self.helmet_walk_frames, self.helmet_attack_frames,  # 定义帧集合列表
                      self.walk_frames, self.attack_frames, self.losthead_walk_frames,
                      self.losthead_attack_frames, self.die_frames, self.boomdie_frames]
        name_list = [helmet_walk_name, helmet_attack_name,  # 定义帧名称列表
                     walk_name, attack_name, losthead_walk_name,
                     losthead_attack_name, die_name, boomdie_name]

        for i, name in enumerate(name_list):  # 遍历帧名称列表
            if name == c.BOOMDIE:  # 如果帧名称为爆炸死亡帧
                color = c.BLACK  # 设置颜色为黑色
            else:
                color = c.WHITE  # 否则设置颜色为白色
            self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'],
                            color)  # 调用loadFrames方法加载帧图像，传入帧集合、名称、x坐标和颜色

        self.frames = self.helmet_walk_frames  # 设置当前帧集合为头盔行走帧集合


class NewspaperZombie(Zombie):  # 定义报纸僵尸类，继承自Zombie类
    def __init__(self, x, y, head_group):  # 初始化方法，接受x、y坐标和head_group参数
        Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, c.NEWSPAPER_HEALTH, head_group)  # 调用父类Zombie的初始化方法，传入x、y坐标、常量NEWSPAPER_ZOMBIE、NEWSPAPER_HEALTH和head_group参数
        self.helmet = True  # 设置头盔属性为True

    def loadImages(self):  # 定义加载图像的方法
        self.helmet_walk_frames = []  # 初始化头盔行走帧集合
        self.helmet_attack_frames = []  # 初始化头盔攻击帧集合
        self.walk_frames = []  # 初始化行走帧集合
        self.attack_frames = []  # 初始化攻击帧集合
        self.losthead_walk_frames = []  # 初始化失去头部后的行走帧集合
        self.losthead_attack_frames = []  # 初始化失去头部后的攻击帧集合
        self.die_frames = []  # 初始化死亡帧集合
        self.boomdie_frames = []  # 初始化爆炸死亡帧集合

        helmet_walk_name = self.name  # 获取头盔行走帧的名称
        helmet_attack_name = self.name + 'Attack'  # 获取头盔攻击帧的名称
        walk_name = self.name + 'NoPaper'  # 获取无报纸的行走帧的名称
        attack_name = self.name + 'NoPaperAttack'  # 获取无报纸的攻击帧的名称
        losthead_walk_name = self.name + 'LostHead'  # 获取失去头部后的行走帧的名称
        losthead_attack_name = self.name + 'LostHeadAttack'  # 获取失去头部后的攻击帧的名称
        die_name = self.name + 'Die'  # 获取死亡帧的名称
        boomdie_name = c.BOOMDIE  # 获取爆炸死亡帧的名称

        frame_list = [self.helmet_walk_frames, self.helmet_attack_frames,  # 定义帧集合列表
                      self.walk_frames, self.attack_frames, self.losthead_walk_frames,
                      self.losthead_attack_frames, self.die_frames, self.boomdie_frames]
        name_list = [helmet_walk_name, helmet_attack_name,  # 定义帧名称列表
                     walk_name, attack_name, losthead_walk_name,
                     losthead_attack_name, die_name, boomdie_name]

        for i, name in enumerate(name_list):  # 遍历帧名称列表
            if name == c.BOOMDIE:  # 如果帧名称为爆炸死亡帧
                color = c.BLACK  # 设置颜色为黑色
            else:
                color = c.WHITE  # 否则设置颜色为白色
            self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'], color)  # 调用loadFrames方法加载帧图像，传入帧集合、名称、x坐标和颜色

        self.frames = self.helmet_walk_frames  # 设置当前帧集合为头盔行走帧集合
